home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / pack / xfh132.lzh / XFH / src / lock.c < prev    next >
C/C++ Source or Header  |  1993-01-19  |  19KB  |  609 lines

  1. /* lock.c - Lock-related stuff for the cfs file system. 
  2.    Copyright (C) 1991, 1992, 1993 Kristian Nielsen.
  3.  
  4.    This file is part of XFH, the compressing file system handler.
  5.  
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2 of the License, or
  9.    (at your option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            */
  19.  
  20. /* $Log:    lock.c,v $
  21.  * Revision 1.2  93/01/14  15:29:20  Kristian
  22.  * Added RCS keywords.
  23.  * 
  24.  */
  25.  
  26.  
  27. #include "CFS.h"
  28.  
  29. #include <string.h>
  30.  
  31. #include <dossupport.h>
  32.  
  33.  
  34. /*
  35.  * RawCFSLock() is the low-lewel LOCATE_OBJECT function of the CFS file
  36.  * system. It takes a simple filename (that is, no path specification),
  37.  * a lock to the parent directory, and a 'mode' value as arguments. A
  38.  * special case occurs for a null name, in which case it just returns
  39.  * a copy of the passed lock.
  40.  * NOTE: 'directory/' is a valid name iff it's a directory.
  41.  */
  42.  
  43. struct CFSLock *RawCFSLock(glb glob, struct CFSLock *lock,
  44.                         char * name, LONG mode ){
  45.    LONG saveioerr;
  46.     
  47.    if( name && *name ){
  48.  
  49.       /* Here is the place to check whether the lock refers to a
  50.        * directory in the underlying file system, or if it is in fact
  51.        * a directory in an archieve. This code is for the former case: */
  52.  
  53.       if( lock->objtype == XOBJECT ){
  54.          struct FileLock *xlock;
  55.  
  56.          if( !(xlock=xLock(glob,lock->xlock,name,mode)) ){
  57.             debug(("Error: RawCFSLock(): Could not obtain lock: %ld.\n",glob->ioerr));
  58.             return NULL;
  59.          }
  60.          if( !xExamine( glob, xlock, &glob->fib1 ) ){
  61.             debug(("Error: RawCFSLock(): Cannot examine() object: %ld\n",glob->ioerr));
  62.             saveioerr = glob->ioerr;
  63.             xUnLock( glob, xlock );
  64.             glob->ioerr = saveioerr;
  65.             return NULL;
  66.          }
  67.          if( glob->fib1.fib_DirEntryType > 0 ){
  68.             struct CFSLock *newlock;
  69.  
  70.             /* A directory. */
  71.             newlock = XObjMakeLock(glob, xlock, mode);
  72.             if( !newlock ){
  73.                saveioerr = glob->ioerr;
  74.                xUnLock(glob, xlock);
  75.                glob->ioerr = saveioerr;
  76.             }
  77.             return newlock;
  78.          }else{
  79.             struct FileHandle *xfh;
  80.             LONG filetype;
  81.             
  82.             /* A plain file. Determine its type. */
  83.             /* First open the file. If the lock is to be exclusive, */
  84.             /* we need to xUnLock() it while examining the file (BAD!) */
  85.             /* This means that there's an ever so slight change that */
  86.             /* the file will go away inbetween the xClose() and xLock(). */
  87.             /* It might even have come back in a new disguise! sigh... */
  88.             
  89.             if( mode == EXCLUSIVE_LOCK ){
  90.                debug(("RawCFSLock(): Temporarely UnLock()'ing...\n"));
  91.                xUnLock(glob, xlock);
  92.                xlock = NULL;
  93.                xfh = xOpen( glob, lock->xlock, name, MODE_OLDFILE );
  94.             }else{
  95.                xfh = xOpenFromCopyOfLock( glob, xlock );
  96.             }
  97.             if( !xfh ){
  98.                debug(("Error: RawCFSLock(): Cannot Open() file: %ld.\n",glob->ioerr));
  99.                if( xlock ){
  100.                   saveioerr = glob->ioerr;
  101.                   xUnLock(glob, xlock);
  102.                   glob->ioerr = saveioerr;
  103.                }
  104.                return NULL;
  105.             }
  106.             filetype = xFileType(glob, xfh);
  107.             xClose(glob, xfh);
  108.             if(!xlock){
  109.                if( !(xlock=xLock(glob,lock->xlock,name,mode)) ){
  110.                   debug(("Error: RawCFSLock(): Could not re-Lock() the file: %ld.\n",glob->ioerr));
  111.                   return NULL;
  112.                }
  113.             }
  114.             /* ToDo: this shouldn't be implemented as an ugly switch(). */
  115.             switch(filetype){
  116.                case XOBJECT:{
  117.                   struct CFSLock *newlock;
  118.                   
  119.                   newlock = XObjMakeLock(glob, xlock, mode);
  120.                   if( !newlock ){
  121.                      saveioerr = glob->ioerr;
  122.                      xUnLock( glob, xlock );
  123.                      glob->ioerr = saveioerr;
  124.                   }
  125.                   return newlock;
  126.                }
  127.                case XPKOBJECT:{
  128.                   struct XpkLock *newlock;
  129.                   
  130.                   newlock = XpkMakeLock(glob, xlock, mode);
  131.                   if( !newlock ){
  132.                      saveioerr = glob->ioerr;
  133.                      xUnLock(glob, xlock);
  134.                      glob->ioerr = saveioerr;
  135.                   }
  136.                   return (struct CFSLock *)newlock;
  137.                }
  138.                default:
  139.                   debug(("ERROR: RawCFSLock(): unsupported file type %ld.\n",filetype));
  140.                   glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  141.                   return NULL;
  142.             }
  143.          }
  144.       }else{
  145.          debug(("** PANIC **: bad object type in lock: %ld\n",lock->objtype));
  146.          glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  147.          return NULL;
  148.       }
  149.    }else{
  150.       /* A Null name was passed. If the parent lock is of the right type,
  151.        * just DupLock() it. Otherwise, signal an error.
  152.        * (Duplock() will catch the case of an exclusive lock).
  153.        */
  154.       if( mode == lock-> mode ){
  155.          return CFSDupLock( glob, lock );
  156.       }else{
  157.          glob->ioerr = ERROR_OBJECT_IN_USE;
  158.          return NULL;
  159.       }
  160.    }
  161. }
  162.  
  163.  
  164. /* And DOS said: let there be devices...
  165.  * So hardwire a CFSLock to serve as our root lock.
  166.  */
  167. struct CFSLock *makerootlockdayone(glb glob){
  168.    return XObjMakeLock(glob, glob->xrootlock, ACCESS_READ);
  169. }
  170.  
  171.  
  172. /*
  173.  * Create a struct FileLock around a CFSLock for returning to caller.
  174.  */
  175. struct FileLock * CreateFileLock( glb glob, struct CFSLock *lock ){
  176.    struct FileLock *xlock;
  177.    
  178.    if( !dalloc(xlock) ){
  179.       OUTOFMEM;
  180.       return NULL;
  181.    }
  182.    
  183.    /* Place any linking of filelocks into a list here. */
  184.    xlock -> fl_Key = (LONG) lock;
  185.    xlock -> fl_Access = lock -> mode;
  186.    xlock -> fl_Task = glob -> dosport;
  187.    xlock -> fl_Volume = c2b(glob -> volnode);
  188.    
  189.    return xlock;
  190. }
  191.  
  192.  
  193.  
  194. /*
  195.  * This is the function that does all the main parsing of path strings.
  196.  * It's purpose is to lock the parent directory of a file or dir, and
  197.  * return a pointer to the actual filename. A special case occurs for
  198.  * NULL filenames (either "" or "name:") - here the actual lock is
  199.  * returned, and the name set to "".
  200.  *
  201.  * In case of an error, the name is set to "", and a NULL lock is returned.
  202.  *
  203.  * NOTE: This will fail to correctly handle a path like '...//' - it
  204.  * will lock the directory and return a NULL name. This will present
  205.  * a problem if someone tries to obtain an exclusive lock on such a path.
  206.  */
  207.  
  208. struct CFSLock *CFSLockParent( glb glob, struct CFSLock *parentlock,
  209.                           char **nameptr ){
  210.    char *p,*q,*path,*name;
  211.    struct CFSLock *lock,*childlock;
  212.    int len;
  213.    
  214.    
  215.    /* Watch out for a NULL name. */
  216.    if(!*nameptr) *nameptr = "";
  217.    
  218.    /* Allocate a copy of the path so that we can modify it. */
  219.    len = strlen(*nameptr);
  220.    if( !(name = dosalloc( len+1 )) ){
  221.       OUTOFMEM;
  222.       *nameptr += len;       /* Set to empty string. */
  223.       return NULL;
  224.    }
  225.    strcpy( name, *nameptr);
  226.    
  227.    path = name;
  228.  
  229.    /* A NULL parent lock is equal to the rootlock. */
  230.    if(!parentlock) parentlock = glob->rootlock;
  231.    
  232.    /* Now check for an absolute path, ie '...:...' */
  233.    if( p=strchr(name,':') ){
  234.       
  235.       /* Got an absolute path. This is either an assign (or the device /
  236.        * volume name, which is treated the same way), or a root
  237.        * specification (like ':system/cli'). */
  238.  
  239.       if( p==name ){               /* get the root dir. */
  240.          parentlock = glob->rootlock;
  241.       }
  242. #ifndef NONSTRICT
  243.       else{
  244.          /* The assign/device/volume name was used by dos.library to
  245.           * find our process id and the parent lock. It is of no use
  246.           * to the handler.*/
  247.          
  248.          /* 'Assign' allows silly names like '1/2:', but some other
  249.           * commands have trouble with this. Flag these names as invalid. */
  250.           
  251.          if( q=strchr(name,'/') ){
  252.             if( q<p ){
  253.                debug(("Error: silly device name '%s'/n",name));
  254.                glob->ioerr = ERROR_INVALID_COMPONENT_NAME;
  255.                dosfree( name );
  256.                *nameptr += len;
  257.                return NULL;
  258.             }
  259.          }
  260.       }
  261. #endif
  262.  
  263.       path = p+1;     /* Point past ':'. */
  264.  
  265. #ifndef NONSTRICT
  266.       /* Disallow more than one ':' char in name. */
  267.       if( strchr(path,':') ){
  268.          debug(("Error: multiple ':' char in name '%s'.\n",name));
  269.          glob->ioerr = ERROR_INVALID_COMPONENT_NAME;
  270.          dosfree( name);
  271.          *nameptr += len;
  272.          return NULL;
  273.       }
  274. #endif
  275.    
  276.    }
  277.  
  278.    /* Now look through the path specification. */
  279.    
  280.    if( !(lock = CFSDupLock( glob, parentlock )) ){
  281.       /* Couldn't DupLock the parent. Hence we must use a reference. */
  282.       debug(("CFSLockParent(): Cannot DupLock() the passed parent dir: %ld - using reference.\n",glob->ioerr));
  283.       XObjAddReferenceToLock(glob, parentlock);
  284.       lock = parentlock;
  285.       /* NOTE: We now have a dangerous double reference to the
  286.        * lock. Notably, the lock will be CFSUnLock()'ed two
  287.        * times.
  288.       */
  289.    }
  290.    
  291.    for(;;){
  292.       p = path;
  293.       if( !*p ) break;  /* If p is the null string, then lock is ok now. */
  294.       path = strchr( p, '/' );
  295.       if( path ){
  296.          *path++ = '\0';
  297.          if( !*path && path != p+1 ){
  298.             break;                         /* Last component is 'name/'. */
  299.          }
  300.       }else{
  301.          break;                            /* Last component is 'name'. */
  302.       }
  303.  
  304.       /* At this point, p holds a null-terminated path component. */
  305.       
  306.       childlock = p+1 == path ?
  307.          CFSParentDir(glob,lock) :
  308.          RawCFSLock(glob,lock,p,SHARED_LOCK);
  309.       if( !childlock ){
  310.          LONG saveioerr;
  311.          
  312.          /* Some kind of error happened while locking the path component.
  313.           * Report this error back to caller. */
  314.          
  315.          saveioerr = glob->ioerr;    /* Save I/O error code. */
  316.          CFSUnLock( glob, lock);
  317.          if( p+1 == path && !glob->ioerr) /* Attempt to use '/' past root */
  318.             glob->ioerr = ERROR_OBJECT_NOT_FOUND;
  319.          else
  320.             glob->ioerr = saveioerr;  /* Restore for IoErr(). */
  321.          dosfree( name );
  322.          *nameptr += len;
  323.          return NULL;
  324.       }
  325.       CFSUnLock( glob, lock);
  326.       lock=childlock;
  327.  
  328.       if( !CFSExamine(glob, childlock, &glob->fib1) ){
  329.          /* Error examining component. */
  330.  
  331.          CFSUnLock(glob, lock);
  332.          dosfree( name );
  333.          *nameptr += len;
  334.          return NULL;
  335.       }
  336.       
  337.       if( glob->fib1.fib_DirEntryType < 0 ){
  338.          /* this component in the path is not a directory, so return 
  339.           * an error. */
  340.          
  341.          debug(("Error: CFSLockParent(): Plain file used in path.\n"));
  342.          CFSUnLock(glob, lock);
  343.          glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  344.          dosfree( name );
  345.          *nameptr += len;
  346.          return NULL;
  347.       }
  348.    }
  349.  
  350.    *nameptr += (p - name);    /* Point to equivalent of *p in 'name'. */
  351.    dosfree( name );
  352.    return lock;
  353. }
  354.  
  355.  
  356. /*
  357.  * This function handles the ACTION_LOCATE_OBJECT request.
  358.  */
  359.  
  360. struct CFSLock * CFSLock(glb glob,struct CFSLock * parentlock,
  361.                           char * name,LONG mode){
  362.    struct CFSLock *lock,*parent;
  363.    LONG ioerrsave;
  364.    
  365.    /* Lock the parent directory, and set 'name' to point to the actual
  366.     * name. For a path like 'name:', lock the file/dir and point name to
  367.     * "" (RawCFSLock() will handle this case).
  368.     */
  369.    if(!(parent = CFSLockParent(glob, parentlock, &name ))){
  370.       return NULL;
  371.    }
  372.    debug(("CFSLock: parent=%lx, name='%s'\n",parent,name));
  373.    /* Now Lock the file or dir. */
  374.    lock = RawCFSLock( glob, parent, name, mode );
  375.    ioerrsave = glob->ioerr;
  376.    CFSUnLock( glob, parent );
  377.    glob->ioerr = ioerrsave;
  378.    return lock;
  379. }
  380.  
  381.  
  382. struct CFSLock *CFSDupLock( glb glob, struct CFSLock *lock ){
  383.    
  384.    if( !lock ) return 0L;
  385.    return (*lock->f->DupLock) (glob,lock);
  386. }
  387.  
  388.  
  389. struct CFSLock *CFSParentDir( glb glob, struct CFSLock *lock){
  390.    
  391.    if( !lock ) return NULL;
  392.    else if(!lock->f){
  393.       debug(("** PANIC **: CFSParentDir(): NULL action function.\n"));
  394.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  395.       return DOSFALSE;
  396.    }else return (*lock->f->Parent)(glob, lock);
  397. }
  398.  
  399.  
  400. BOOL CFSUnLock( glb glob,struct CFSLock *lock){
  401.  
  402.    if( !lock ) return 0L;       /* No really sensible error possible. */
  403.    else if(!lock->f){
  404.       debug(("** PANIC **: CFSUnLock(): NULL action function.\n"));
  405.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  406.       return DOSFALSE;
  407.    }else return (*lock->f->UnLock)(glob, lock);
  408. }
  409.  
  410.  
  411. BOOL CFSExamine(glb glob, struct CFSLock *lock, struct FileInfoBlock *fib){
  412.  
  413.    if( !lock ){
  414.       return DOSFALSE;       /* No really sensible error possible. */
  415.    }else if( lock->f ){
  416.       return (*lock->f->Examine)( glob, lock, fib );
  417.    } else {
  418.       debug(("** PANIC **: NULL object action func Examine() in lock.\n"));
  419.       return DOSFALSE;
  420.    }
  421. }
  422.  
  423.  
  424. BOOL CFSExamineNext(glb glob, struct CFSLock *lock, struct FileInfoBlock *fib){
  425.  
  426.    if( !lock ){
  427.       return DOSFALSE;       /* No really sensible error possible. */
  428.    }else if( lock->f ){
  429.       return (*lock->f->ExNext)( glob, lock, fib );
  430.    } else {
  431.       debug(("** PANIC **: NULL object action func ExNext() in lock.\n"));
  432.       return DOSFALSE;
  433.    }
  434. }
  435.  
  436.  
  437. struct CFSLock *CFSCreateDir( glb glob, struct CFSLock *parent, char *name ){
  438.    struct CFSLock *lock;
  439.    
  440.    /* Lock the parent directory, and set 'name' to point to the actual
  441.     * name. For a path like 'name:', lock the file/dir and point name to
  442.     * "" (RawCFSLock() will handle this case).
  443.     */
  444.    if(!(parent = CFSLockParent(glob, parent, &name ))){
  445.       return NULL;
  446.    }else if( parent->f ){
  447.       LONG saveioerr;
  448.       
  449.       lock = (*parent->f->CreateDir)( glob, parent, name );
  450.       if( !lock ) saveioerr = glob->ioerr;
  451.       CFSUnLock( glob, parent );
  452.       if( !lock ) glob->ioerr = saveioerr;
  453.       return lock;
  454.    }else{
  455.       debug(("** PANIC **: NULL object action func CreateDir() in lock.\n"));
  456.       CFSUnLock( glob, parent );
  457.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  458.       return NULL;
  459.    }
  460. }
  461.  
  462.  
  463. /* CFSDeleteFile(): Delete a file or directory.
  464.  *
  465.  * Just passes control to the appropriate lock-specific call.
  466.  * NOTE: It's up to the lock-specific functions to check that an attempt
  467.  * to delete a non-empty directory is rejected.
  468.  */
  469. BOOL CFSDeleteFile( glb glob, struct CFSLock *parent, char *name ){
  470.    
  471.    if(!(parent = CFSLockParent(glob, parent, &name ))){
  472.       return DOSFALSE;
  473.    }else if( parent->f ){
  474.       LONG saveioerr;
  475.       BOOL err;
  476.       
  477.       err = (*parent->f->DeleteFile)( glob, parent, name );
  478.       if( !err ) saveioerr = glob->ioerr;
  479.       CFSUnLock( glob, parent );
  480.       if( !err ) glob->ioerr = saveioerr;
  481.       return err;
  482.    }else{
  483.       debug(("** PANIC **: NULL object action func DeleteFile() in lock.\n"));
  484.       CFSUnLock( glob, parent );
  485.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  486.       return DOSFALSE;
  487.    }
  488. }
  489.  
  490.  
  491. /* CfsRename(): Rename files within the file system.
  492.  *
  493.  * A problem arises if someone tries to rename between two directory-
  494.  * locks of different types (ie. a lharc-archieve and an UFS directory).
  495.  * This function passes control to the FROM-locktype rename function. It's
  496.  * up to this function to check the type of the destination directory
  497.  * and take an appropriate action.
  498.  */
  499. BOOL CFSRename( glb glob, struct CFSLock *parent1, char *name1, struct CFSLock *parent2, char *name2 ){
  500.    
  501.    if(!(parent1 = CFSLockParent(glob, parent1, &name1 ))){
  502.       return DOSFALSE;
  503.    }
  504.    if(!(parent2 = CFSLockParent(glob, parent2, &name2 ))){
  505.       LONG saveioerr = glob->ioerr;
  506.       CFSUnLock( glob, parent1 );
  507.       glob->ioerr = saveioerr;
  508.       return DOSFALSE;
  509.    }
  510.  
  511.    if( parent1->f ){
  512.       LONG saveioerr;
  513.       BOOL err;
  514.       
  515.       err = (*parent1->f->Rename)( glob, parent1, name1, parent2, name2 );
  516.       if( !err ) saveioerr = glob->ioerr;
  517.       CFSUnLock( glob, parent1 );
  518.       CFSUnLock( glob, parent2 );
  519.       if( !err ) glob->ioerr = saveioerr;
  520.       return err;
  521.    }else{
  522.       debug(("** PANIC **: NULL object action func Rename() in lock.\n"));
  523.       CFSUnLock( glob, parent1 );
  524.       CFSUnLock( glob, parent2 );
  525.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  526.       return DOSFALSE;
  527.    }
  528. }
  529.  
  530.  
  531. BOOL CFSSetProtection( glb glob, struct CFSLock *parent, char *name, LONG bits ){
  532.    
  533.    if(!(parent = CFSLockParent(glob, parent, &name ))){
  534.       return DOSFALSE;
  535.    }else if( parent->f ){
  536.       LONG saveioerr;
  537.       BOOL err;
  538.       
  539.       err = (*parent->f->SetProtection)( glob, parent, name, bits );
  540.       if( !err ) saveioerr = glob->ioerr;
  541.       CFSUnLock( glob, parent );
  542.       if( !err ) glob->ioerr = saveioerr;
  543.       return err;
  544.    }else{
  545.       debug(("** PANIC **: NULL object action func SetProtection() in lock.\n"));
  546.       CFSUnLock( glob, parent );
  547.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  548.       return DOSFALSE;
  549.    }
  550. }
  551.  
  552.  
  553. BOOL CFSSetComment( glb glob, struct CFSLock *parent, char *name, char *comment ){
  554.    
  555.    if(!(parent = CFSLockParent(glob, parent, &name ))){
  556.       return DOSFALSE;
  557.    }else if( parent->f ){
  558.       LONG saveioerr;
  559.       BOOL err;
  560.       
  561.       err = (*parent->f->SetComment)( glob, parent, name, comment );
  562.       if( !err ) saveioerr = glob->ioerr;
  563.       CFSUnLock( glob, parent );
  564.       if( !err ) glob->ioerr = saveioerr;
  565.       return err;
  566.    }else{
  567.       debug(("** PANIC **: NULL object action func SetComment() in lock.\n"));
  568.       CFSUnLock( glob, parent );
  569.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  570.       return DOSFALSE;
  571.    }
  572. }
  573.  
  574.  
  575. BOOL CFSSetDate( glb glob, struct CFSLock *parent, char *name, struct DateStamp *ds ){
  576.    
  577.    if(!(parent = CFSLockParent(glob, parent, &name ))){
  578.       return DOSFALSE;
  579.    }else if( parent->f ){
  580.       LONG saveioerr;
  581.       BOOL err;
  582.       
  583.       err = (*parent->f->SetFileDate)( glob, parent, name, ds );
  584.       if( !err ) saveioerr = glob->ioerr;
  585.       CFSUnLock( glob, parent );
  586.       if( !err ) glob->ioerr = saveioerr;
  587.       return err;
  588.    }else{
  589.       debug(("** PANIC **: NULL object action func SetDate() in lock.\n"));
  590.       CFSUnLock( glob, parent );
  591.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  592.       return DOSFALSE;
  593.    }
  594. }
  595.  
  596.  
  597. BOOL CFSSameLock( glb glob, struct CFSLock *l1, struct CFSLock *l2 ){
  598.    if(!l1 || !l2) return l1==l2 ? TRUE : FALSE;
  599.    if( l1->objtype != l2->objtype ) return FALSE;
  600.    if( !l1->f ){
  601.       debug(("** PANIC **: CFSSameLock(): Bad action func in lock.\n"));
  602.       glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
  603.       return FALSE;
  604.    }else return (*l1->f->SameLock)(glob, l1, l2);
  605. }
  606.  
  607.  
  608. /* End of lock.c */
  609.